package com.markyao.recos.raft.raftRole;

import com.github.benmanes.caffeine.cache.Cache;
import com.markyao.utils.CacheUtils;
import com.markyao.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j(topic = "m.AbstractRaftRole")
public abstract class AbstractRaftRole {
    protected int roleState;//三种角色: 1.追随者 2.候选人 3.领导者
    protected boolean vote; //是否已经投票
    protected AtomicInteger score; //获得的票数
    protected List<AbstractRaftRole> raftRoleList;
    protected String[] groupsAds;
    protected final String host;
    protected final int port;
    protected final String username;
    protected final String password;
    protected Map<String,String> tokenMap;
    protected int aliveSize;
    protected int safeScore;
    protected final int electionTimeWindow=3000;
    protected boolean isOnload;
    protected boolean isBoom;
    protected Cache<String,Integer> boomState;


    public AbstractRaftRole(String host,int port,String username,String password) {
        this.host=host;
        this.port=port;
        this.username=username;
        this.password=password;
        roleState=1;
        vote=false;
        score=new AtomicInteger(0);
        raftRoleList=new ArrayList<>(16);
        this.tokenMap=new ConcurrentHashMap<String,String>();
        this.isOnload=true;
        this.isBoom=false;
        this.boomState= CacheUtils.getStrIntCache(1);

    }

    public boolean isOnload(){
        return isOnload;
    }

    public String[] getGroupsAds() {
        return groupsAds;
    }

    public void setGroupsAds(String[] groupsAds) {
        this.groupsAds = groupsAds;
        this.aliveSize=groupsAds.length+1;
    }

    public boolean isBoom() {
        try {
            Integer boom = boomState.getIfPresent("boom");
            if (boom!=null && boom==1){
                log.info("boom...");
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }

    public void setAliveSize(int aliveSize) {
        this.aliveSize = aliveSize;
    }

    public int getAliveSize() {
        return aliveSize;
    }

    public int getSafeScore() {
        return safeScore;
    }

    public void setSafeScore(int safeScore) {
        this.safeScore = safeScore;
    }

    public int getRoleState() {
        return roleState;
    }

    public void setRoleState(int roleState) {
        this.roleState = roleState;
    }

    public boolean isVote() {
        return vote;
    }

    public void setVote(boolean vote) {
        this.vote = vote;
    }

    public AtomicInteger getScore() {
        return score;
    }

    public void setScore(AtomicInteger score) {
        this.score = score;
    }

    public List<AbstractRaftRole> getRaftRoleList() {
        return raftRoleList;
    }

    public void setRaftRoleList(List<AbstractRaftRole> raftRoleList) {
        this.raftRoleList = raftRoleList;
    }

    public String getHost() {
        return host;
    }

    public int getPort() {
        return port;
    }

    public abstract void election();

    public  abstract Result vote(Long startTime,String targetAddress);

    public abstract void sendHeartBeat(int ret);

    public abstract void recvHeartBeat();

    protected abstract void startSendHeartBeat();
    public void shiftCandidate(){
        this.vote=true;
        this.score.set(1);
        this.roleState=2;
    }

    public void shiftFollower(){
        this.vote=false;
        this.score.set(0);
        this.roleState=1;
    }

    public void shiftLeader(){
        this.vote=true;
        this.roleState=3;
    }


    public abstract void connenct2Recos();

    public abstract boolean askLeader(String host, int port);


    class BoomTimer extends Thread{

        int mills;


        public BoomTimer(int mills) {
            this.mills = mills;
        }

        @Override
        public void run() {
            try {
                System.out.println("boomTimer...");
                Thread.sleep(mills);
                isBoom=false;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

